#include "muduo/proto/codec.h"
#include "muduo/proto/dispatcher.h"
#include "protobuf.pb.h"
#include "muduo/base/Logging.h"
#include "muduo/base/Mutex.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"
#include <iostream>
#include <string>
#include <functional>
#include <unordered_map>
using namespace std;
using namespace placeholders;

class Server
{
    typedef std::shared_ptr<google::protobuf::Message> MessagePtr;
    typedef std::shared_ptr<ns_cr::TranslateReq> TranslateReqPtr;
    typedef std::shared_ptr<ns_cr::AddReq> AddReqPtr;

public:
    Server(int port)
        : _svr(&_loop, muduo::net::InetAddress("0.0.0.0", port),
               "Server", muduo::net::TcpServer::kReusePort),
          _dispatcher(std::bind(&Server::unkonwnmessage, this, _1, _2, _3)),
          _codec(std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, _1, _2, _3))
    {
        // 注册_dispatcher业务请求处理函数
        _dispatcher.registerMessageCallback<ns_cr::TranslateReq>(
            std::bind(&Server::mytranslate, this, _1, _2, _3));

        _dispatcher.registerMessageCallback<ns_cr::AddReq>(
            std::bind(&Server::myadd, this, _1, _2, _3));

        // 连接回调处理
        _svr.setConnectionCallback(std::bind(&Server::myconnect, this, _1));

        // 设置成协议处理器，在协议处理结束后,其内部会再次调用请求分发器执行对应的回调函数
        _svr.setMessageCallback(std::bind(
            &ProtobufCodec::onMessage, &_codec, _1, _2, _3));
    }
    void start()
    {
        _svr.start(); // 创建套接字+将套接字设置到_loop(epoll)事件
        _loop.loop(); // 死循环阻塞,等待监听套接字事件到来,然后进行IO处理,回调_svr里设置的的回调函数
    }

private:
    string translate(const string &info)
    {
        static unordered_map<string, string> dict = {
            {"hello", "你好"},
            {"计算机", "computer"},
            {"向左", "turn left"},
            {"向右", "turn right"},
            {"向前", "forward"},
            {"向后", "backwards"}};
        if (!dict.count(info))
            return "not find!";
        else
            return dict[info];
    }
    // 翻译处理函数
    void mytranslate(const muduo::net::TcpConnectionPtr &conn,
                     const TranslateReqPtr &message, muduo::Timestamp)
    {
        // 1.提取数据
        string inform = message->mes();

        // 2.信息处理请求信息(翻译)
        string rsp_info = translate(inform);

        // 3.设置protobuf的TranslateRsp对象的成员
        ns_cr::TranslateRsp rsp;
        rsp.set_mes(rsp_info);

        // 4.数据序列化发送
        _codec.send(conn, rsp);
    }

    // 加法处理函数
    void myadd(const muduo::net::TcpConnectionPtr &conn,
               const AddReqPtr &message, muduo::Timestamp)
    {
        // 1.提取数据
        int num1 = message->num1();
        int num2 = message->num2();

        // 2.信息处理请求信息(翻译)
        int result = num1 + num2;

        // 3.设置protobuf的TranslateRsp对象的成员
        ns_cr::AddRsp rsp;
        rsp.set_result(result);

        // 4.数据序列化发送
        _codec.send(conn, rsp);
    }

    // 收到未知消息处理函数
    void unkonwnmessage(const muduo::net::TcpConnectionPtr &conn,
                        const MessagePtr &message, muduo::Timestamp)
    {
        LOG_INFO << "未知信息: " << message->GetTypeName();
        conn->shutdown();
    }

    // 连接就绪(listen_socket)就绪的回调函数
    void myconnect(const muduo::net::TcpConnectionPtr &conn)
    {
        if (conn->connected())
        {
            cout << "新连接建立成功" << endl;
        }
        else
        {
            cout << "连接关闭" << endl;
        }
    }

private: //(_svr内部调用_codec,_codec内部调用_dispatcher)
    // EventLoop对象必须在TcpServer对象之前，因为TcpServer对象在初始化列表中用到了EventLoop
    muduo::net::EventLoop _loop;    // epoll事件监听+IO操作
    muduo::net::TcpServer _svr;     // 设置回调处理数据请求
    ProtobufDispatcher _dispatcher; // 请求分发器-注册请求处理函数
    ProtobufCodec _codec;           // 协议处理器-将收到的请求数据进行协议处理
};

int main()
{
    Server svr(6666);
    svr.start();

    return 0;
}